home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-21 / dvcron21.zip / CRON.C < prev    next >
Text File  |  1992-01-19  |  16KB  |  517 lines

  1. /*
  2.   Copyright (c) 1991 -- Kyle A. York
  3.   copy / use / modify at will -- see CRON.DOC for details
  4. */
  5.  
  6. #include <dir.h>
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include <time.h>
  10. #include <process.h>
  11. #include <fcntl.h>
  12. #include <stdlib.h>
  13. #include <io.h>
  14. #include <tvapi.h>
  15. #include <ctype.h>
  16. #include <sys\stat.h>
  17. #include <alloc.h>
  18. #include "pif.h"
  19. #include "getopt.h"
  20.  
  21. extern int directvideo=0;
  22. unsigned _stklen=2048;
  23.  
  24. char *buffer,                /* buffer for CRONTAB file. set once at start */
  25.      crontabname[MAXPATH],   /* full path to 'crontab' */
  26.      cronlogname[MAXPATH],   /* full path to 'cron.log'*/
  27.      crontemplate[MAXPATH],  /* full path to template ".dvp" file */
  28.      locallog[MAXPATH]="";
  29. int  bufsize;                /* size of input buffer   */
  30. time_t now;                  /* current time           */
  31.  
  32. /*
  33.   this function seems to be missing from the DVGLUE library.
  34.   it pops-up an error window & displays the message. then it waits
  35.   for ESCAPE or a mouse button to be pressed before returning
  36. */
  37. void DVError(char *fmt, ...)
  38. {
  39.   struct REGPACK regs;
  40.   OBJECT         mytask;
  41.   char           errmsg[256],
  42.                 *tmp=errmsg;
  43.   va_list        ap;
  44.   int            rows=1;
  45.  
  46.   va_start(ap, fmt);
  47.   vsprintf(errmsg, fmt, ap);
  48.   va_end(ap);
  49.  
  50.   while (*tmp)                             /* count # of rows used */
  51.     if (*(tmp++) == '\n')                  /* by message */
  52.       rows++;
  53.   mytask=TVmytask();
  54.   regs.r_bx=0x4000 + 0x2000 + strlen(errmsg);
  55.   regs.r_es=FP_SEG(errmsg);
  56.   regs.r_di=FP_OFF(errmsg);
  57.   regs.r_cx=0x5000 | rows;
  58.   regs.r_dx=FP_SEG(mytask);
  59.   regs.r_ax=0x101f;
  60.   intr(0x15, ®s);
  61. }
  62.  
  63. /*
  64.   write info to log file
  65.   (1) open logfile
  66.   (2) write info with timestamp
  67.   (3) close file
  68. */
  69. void cronlog(char *fmt, ...)
  70. {
  71.   FILE   *logfile;
  72.   char    logstr[256];
  73.   va_list ap;
  74.  
  75.   if (!*cronlogname && !*locallog)
  76.     return;
  77.   va_start(ap, fmt);
  78.   vsprintf(logstr, fmt, ap);
  79.   va_end(ap);
  80.   logfile=fopen(*locallog ? locallog : cronlogname, "at");
  81.   printf("%24.24s: %s\n", ctime(&now), logstr);
  82.   if (logfile) {
  83.     fprintf(logfile, "%24.24s: %s\n", ctime(&now), logstr);
  84.     fclose(logfile);
  85.   } else
  86.     fprintf(stderr, "cannot open logfile {%s}\n",
  87.       *locallog ? locallog : cronlogname);
  88. }
  89.  
  90. /*
  91.   read the CRON file if necessary
  92.   1st call :         open 'crontab'
  93.   successive calls : check file time with last read, if updated, reread
  94.   note: crontab is open FOR THE DURATION OF THE PROGRAM. it is NEVER closed
  95. */
  96. void ReadCronFile(void)
  97. {
  98.   struct ftime        new;                   /* file time now  */
  99.   static struct ftime old;                   /* last file time */
  100.   static int          handle=-1;
  101.   int                 bytesread;
  102.  
  103.   if (handle < 0) {
  104.     old.ft_day=0;                            /* force new read */
  105.     handle=open(crontabname,                 /* name of file   */
  106.                 O_RDONLY | O_TEXT | O_CREAT, /* used to open normal file */
  107.                 S_IREAD | S_IWRITE);         /* used if file created     */
  108.     if (handle < 0) {                        /* if un-openable, abort    */
  109.       DVError("unable to open crontab file");
  110.       exit(1);
  111.     } else
  112.       cronlog("{%s} opened successfully", crontabname);
  113.   }
  114.   getftime(handle, &new);                    /* get timestamp on file */
  115.   if (memcmp(&new, &old, sizeof(new))) {     /* if unequal, re-read file */
  116.     old=new;                                 /* update last read */
  117.     cronlog("CRONTAB core updated");
  118.     lseek(handle, 0, SEEK_SET);              /* rewind file      */
  119.     bytesread=read(handle, buffer, min(bufsize, filelength(handle)));
  120.     buffer[bytesread]=0;
  121.     if (filelength(handle) >= bufsize)
  122.       cronlog("crontab file overflowed buffer. truncated.");
  123.   }
  124. }
  125.  
  126. /*
  127.   skip string ptr over spaces & tabs
  128.   cannot use isspace() as it also skips c/r, l/f, f/f and some others
  129. */
  130. void SkipSpace(char **spc)
  131. {
  132.   while ((**spc == ' ') || (**spc == 9))
  133.     (*spc)++;
  134. }
  135.  
  136. /*
  137.   skip string ptr over a signed integer
  138. */
  139. void SkipNum(char **spc)
  140. {
  141.   SkipSpace(spc);
  142.   if (**spc == '-')
  143.    (*spc)++;
  144.   while (isdigit(**spc))
  145.     (*spc)++;
  146. }
  147.  
  148. /*
  149.   skip string ptr until a space is found
  150. */
  151. void SkipNonSpc(char **spc)
  152. {
  153.   while (**spc && !isspace(**spc))
  154.     (*spc)++;
  155. }
  156.  
  157. /*
  158.   given a number list
  159.     eg: 1-9,10,12-14
  160.   check that a number is included in the list
  161. */
  162. int IsNumInList(char *s, int num)
  163. {
  164.   int lo, hi;
  165.   char *list=s;
  166.  
  167.   SkipSpace(&list);
  168.   if (*list == '*')
  169.     return(TRUE);
  170.   while (isdigit(*list)) {
  171.     lo=atoi(list);
  172.     SkipNum(&list);
  173.     if (lo == num)
  174.       return(TRUE);
  175.     else if (*list == '-') {
  176.       list++;
  177.       if (!isdigit(*list))
  178.         return(FALSE);
  179.       hi=atoi(list);
  180.       SkipNum(&list);
  181.       if ((lo <= num) && (num <= hi))
  182.         return(TRUE);
  183.     }
  184.     if (*list == ',')
  185.       list++;
  186.   }
  187.   return(FALSE);
  188. }
  189.  
  190. /*
  191.   call IsNumInList(), then skip field
  192. */
  193. int CheckNumInList(char **s, int num)
  194. {
  195.   int tmp;
  196.  
  197.   tmp=IsNumInList(*s, num);
  198.   SkipNonSpc(s);
  199.   SkipSpace(s);
  200.   return(tmp);
  201. }
  202.  
  203. /*
  204.   begin a new task
  205.   assume preceding flags are checked
  206.   this does the extension parsing for how-to-execute
  207. */
  208. int SpawnPif(char *name, char *parms, int minmem, int maxmem,
  209.                   int maxexp, int hiddenflag, int backflag)
  210. {
  211.   int     handle,
  212.           size,
  213.           t;
  214.   DVPtype pif;
  215.   OBJECT  obj;
  216.   char   ext[MAXEXT],
  217.          tmp[128];
  218.  
  219.   fnsplit(name, NULL, NULL, NULL, ext);
  220.  
  221.   t=(stricmp(ext, ".dvp") == 0);
  222.   handle=open(t ? name : crontemplate, O_BINARY | O_RDONLY);
  223.   if (handle < 0) {
  224.     cronlog("cannot open: %s", t ? name : crontemplate);
  225.     return(-1);
  226.   }
  227.   size=read(handle, &pif, sizeof(pif));
  228.   close(handle);
  229.   if (minmem >= 0)
  230.     pif.minmem=minmem;
  231.   if (maxmem >= 0)
  232.     pif.maxmem=maxmem;
  233.   if (maxexp >= 0)
  234.     pif.maxexpanded=maxexp;
  235.   if (backflag >= 0)
  236.     pif.flags4 |= 0x10;
  237.   if (!stricmp(ext, ".com") || !stricmp(ext, ".exe")) {
  238.     strcpy(pif.path, name);
  239.     pif.autocloseonexit=1;
  240.   }
  241.   if (!stricmp(ext, ".bat")) {
  242.     strcpy(tmp, name);
  243.     strcat(tmp, " ");
  244.     strcat(tmp, parms);
  245.   } else
  246.     strcpy(tmp, parms);
  247.   if (strlen(tmp) > 63) {
  248.     cronlog("parameter string > 63 chars {%s} {%s}", name, parms);
  249.     return(-1);
  250.   }
  251.   strcpy(pif.parameters, tmp);
  252.   pif.flags2=0x20 | (*tmp ? 0x40 : 0x00);
  253.   obj=DVapp_start(&pif, size);
  254.   if (obj && hiddenflag)
  255.     TVapp_hide(obj);
  256.   if (obj)
  257.     cronlog("%s spawned as %08lx", name, obj);
  258.   else
  259.     cronlog("%s <<SPAWN FAILED>>", name);
  260.   return(0);
  261. }
  262.  
  263. /*
  264.   replace all occurences of key in str with rep
  265.   DOES NOT check for out of string space
  266.   returns str
  267. */
  268. char *Replace(char *str, char *key, char *rep)
  269. {
  270.   char *ptr;
  271.  
  272.   ptr=str;                                        /* initialize */
  273.   while (*ptr) {                                  /* while not end of str */
  274.     if (*ptr == '\\') {                           /* check for literal */
  275.       ptr++;                                      /* yes, skip */
  276.       if (*ptr)
  277.         ptr++;
  278.     } else if (memcmp(ptr, key, strlen(key)) == 0) {  /* found replacement? */
  279.       memmove(ptr+strlen(rep),                    /* yes, make space */
  280.               ptr+strlen(key),                    /* or reduce space */
  281.               strlen(ptr)+1-strlen(key));         /* depending on dif */
  282.       memcpy(ptr, rep, strlen(rep));              /* copy in new string */
  283.       ptr+=strlen(rep);                           /* skip new string */
  284.     } else
  285.       ptr++;                                      /* else simply skip char */
  286.   }
  287.   return(str);
  288. }
  289.  
  290. /*
  291.   this does the pre-parsing.
  292. */
  293. void Execute(char *s, struct tm *tm)
  294. {
  295.   char cmd[64],      /* command string (after parse) */
  296.        param[64],    /* parameters (after parse)     */
  297.        tmp[4],       /* temporary storage for itoa() */
  298.        *ptr=s,
  299.        done=0,
  300.        fail;
  301.   int  ii=0,
  302.        minmem=-1,    /* minimum conventional memory required */
  303.        maxmem=-1,    /* maximum conventional memory allowed */
  304.        maxexp=-1,    /* maximum expanded memory allowed */
  305.        num,          /* temp number for conventional memory */
  306.        hiddenflag=0, /* 1 = yes */
  307.        backflag=-1;  /* 1 = start in background,
  308.                         0 = start in foreground,
  309.                         -1 = use default */
  310.  
  311.   do {
  312.     do {                   /* parse for prefixes */
  313.       SkipSpace(&ptr);
  314.       if (*ptr == '-') {
  315.         ptr++;
  316.         switch(*(ptr++)) {
  317.           case 'b': backflag=1; break;
  318.           case 'c': num=atoi(ptr);
  319.                     SkipNum(&ptr);
  320.                     if (num < 0)
  321.                       minmem=-num;
  322.                     else
  323.                       maxmem=num;
  324.                     break;
  325.           case 'e': maxexp=atoi(ptr);
  326.                     SkipNum(&ptr);
  327.                     break;
  328.           case 'h': hiddenflag=1;
  329.                     break;
  330.           case 'l': ptr++;
  331.                     SkipSpace(&ptr);
  332.                     ii=0;
  333.                     while (*ptr != ' ')
  334.                       if (ii < MAXPATH-1)
  335.                         locallog[ii++]=*(ptr++);
  336.                     locallog[ii]=0;
  337.                     if (stricmp(locallog, "-") == 0)
  338.                       *locallog=0;
  339.                     break;
  340.           default:  ptr-=2;
  341.                     done=1;
  342.                     break;
  343.         }
  344.       } else
  345.         done=1;
  346.     } while (!done);
  347.     fail=0;
  348.     for (ii=0;
  349.          *ptr &&                   /* if not end-of-string */
  350.          (*ptr != 9) &&            /* AND not at space/tab/CR */
  351.          (*ptr != ' ') &&
  352.          (*ptr != '\n');
  353.          ii++,
  354.          ptr++) {
  355.       if (*ptr == ';')             /* found a ';'? */
  356.         if (*(ptr+1) == ';') {     /* yes, are there 2 (";;") */
  357.           if (ii < 64)             /* yes, put in string */
  358.             cmd[ii]=*ptr;
  359.           ptr++;                   /* and skip one */
  360.         } else                     /* otherwise, if only one, break */
  361.           break;
  362.       else if (ii < 64)            /* char other than ';', add to str */
  363.         cmd[ii]=*ptr;
  364.     }
  365.     if (ii >= 64) {
  366.       cronlog("program name > 63 characters {%s}", s);
  367.       fail=1;
  368.     } else
  369.       cmd[ii]=0;
  370.     SkipSpace(&ptr);                       /* skip spaces */
  371.     for (ii=0;
  372.          *ptr &&                   /* if not end-of-string */
  373.          (*ptr != '\n');
  374.          ii++,
  375.          ptr++) {
  376.       if (*ptr == ';')             /* found a ';'? */
  377.         if (*(ptr+1) == ';') {     /* yes, are there 2 (";;") */
  378.           if (ii < 64)             /* yes, put in string */
  379.             param[ii]=*ptr;
  380.           ptr++;                   /* and skip one */
  381.         } else                     /* otherwise, if only one, break */
  382.           break;
  383.       else if (ii < 64)            /* char other than ';', add to str */
  384.         param[ii]=*ptr;
  385.     }
  386.     if (*ptr == ';') {                     /* a ';' is a divider between */
  387.       ptr++;                               /* statemenets. if found, incr */
  388.       SkipSpace(&ptr);                     /* and skip spaces */
  389.     }
  390.     if (ii >= 64) {
  391.       cronlog("parameters > 63 characters {%s}", s);
  392.       fail=1;
  393.     } else
  394.       param[ii]=0;
  395.     if (!fail) {
  396.       sprintf(tmp, "%02d", tm->tm_mon); /* do necessary parameter */
  397.       Replace(param, "%M", tmp);        /* replacements */
  398.       sprintf(tmp, "%02d", tm->tm_mday);
  399.       Replace(param, "%D", tmp);
  400.       sprintf(tmp, "%02d", tm->tm_year % 100);
  401.       Replace(param, "%Y", tmp);
  402.       sprintf(tmp, "%02d", tm->tm_hour);
  403.       Replace(param, "%h", tmp);
  404.       sprintf(tmp, "%02d", tm->tm_min);
  405.       Replace(param, "%m", tmp);
  406.       SpawnPif(cmd, param, minmem, maxmem, maxexp, hiddenflag, backflag);
  407.     }
  408.   } while ((*ptr != '\n') && *ptr);
  409.   *locallog=0;
  410. }
  411.  
  412. /*
  413.   this is the loop where stuff actually gets done.
  414.   it checks the core image to see if anything is ready
  415.   to be spawned & sends the necessary data for spawning
  416. */
  417. void DoCronStuff(struct tm *tm)
  418. {
  419.   char *bufptr=buffer,
  420.         in_mday, in_wday, a, b;
  421.  
  422.   while (*bufptr) {
  423.     if (CheckNumInList(&bufptr, tm->tm_min) &&
  424.         CheckNumInList(&bufptr, tm->tm_hour)) {
  425.       a=*bufptr;
  426.       in_mday=CheckNumInList(&bufptr, tm->tm_mday);
  427.       if (CheckNumInList(&bufptr, tm->tm_mon)) {
  428.         b=*bufptr;
  429.         in_wday=CheckNumInList(&bufptr, tm->tm_wday);
  430.         if (((a != '*') && (b != '*') && in_wday && in_mday) ||
  431.             ((a == '*') && in_wday) ||
  432.             ((b == '*') && in_mday))
  433.           Execute(bufptr, tm);
  434.       }
  435.     }
  436.     while ((*bufptr != '\n') && *bufptr)
  437.       bufptr++;
  438.     if (*bufptr == '\n')
  439.       bufptr++;
  440.   }
  441. }
  442.  
  443. void main(int argc, char **argv)
  444. {
  445.   struct tm *tm;                /* structure for more readable time */
  446.   OBJECT     timer;             /* TV timer object */
  447.   char       drive[MAXDRIVE],   /* path to CRON.EXE */
  448.              dir[MAXDIR];
  449.   int        key,
  450.              errflag;
  451.  
  452.   if (!DVinit()) {              /* initialize DV functions */
  453.     fprintf(stderr, "This program requires DesqView to be active\n");
  454.     exit(1);
  455.   }
  456.  
  457.   TVkbd_free(TVmykbd());      /* don't need a keyboard object! */
  458.   TVobq_close(TVmyobq());     /* don't need an object q (or know what one is)*/
  459.   TVmbx_free(TVmymbx());      /* don't expect any mail */
  460.  
  461.   bufsize=1024;
  462.   fnsplit(argv[0], drive, dir, NULL, NULL);
  463.   fnmerge(crontabname, drive, dir, "crontab", NULL);
  464.   fnmerge(cronlogname,  drive, dir, "cron", ".log");
  465.   fnmerge(crontemplate, drive, dir, "crondos", ".dvp");
  466.  
  467.   errflag=0;
  468.   while ((key=getopt(argc, argv, "c:d:l:m:")) != EOF) {
  469.     switch(key) {
  470.       case 'c': strcpy(crontabname, optarg); break;
  471.       case 'd': strcpy(crontemplate, optarg); break;
  472.       case 'l': if (!stricmp(optarg, "-"))
  473.                   *cronlogname=0;
  474.                 else
  475.                   strcpy(cronlogname, optarg);
  476.                 break;
  477.       case 'm': bufsize=atoi(optarg);
  478.                 break;
  479.       default:  errflag=1;
  480.                 break;
  481.     }
  482.   }
  483.   if (errflag) {
  484.     DVError("format:\n\r   %s [-c crontabname] [-d crontemplate] [-l-] "
  485.             "[-l logfilename] [-m memsize]",
  486.              argv[0]);
  487.     exit(1);
  488.   }
  489.   printf("Buffer size: %d\n", bufsize);
  490.   printf("CRONTAB:     %s\n", crontabname);
  491.   printf("Log file:    %s\n", cronlogname);
  492.   printf("Template:    %s\n", crontemplate);
  493.  
  494.   buffer=malloc(bufsize);
  495.   if (!buffer) {              /* allocate buffer */
  496.     DVError("Could not allocate CRONTAB buffer");
  497.     exit(1);
  498.   }
  499.   if (access(crontemplate, 0)) {                /* check that template */
  500.     DVError("Template not found {%s}", crontemplate); /* exists */
  501.     exit(1);
  502.   }
  503.  
  504.   timer=TVtimer_new();             /* initialize timer        */
  505.   do {
  506.     time(&now);                                  /* get current time     */
  507.     tm=localtime(&now);                          /* in structure         */
  508.     tm->tm_mon++;        /* local time returns month from 0, we want from 1*/
  509.     TVtimer_begin(timer, 100*(60-tm->tm_sec));   /* start countdown until
  510.                                                     next minute */
  511.     ReadCronFile();                              /* load the CRON file */
  512.     DoCronStuff(tm);                             /* execute instructions */
  513.     TVtimer_wait(timer);                         /* give-up CPU until
  514.                                                     counter reaches 0 */
  515.   } while (1);                                   /* repeat indefinetly */
  516. }
  517.